#ifndef __G_SKELETON_H__
#define __G_SKELETON_H__

#include "../skelanim/skeleton.h"
#include "../typedefs.h"

#include "../filter/filter.h"

/// This class extends the original hierarchical 
/// skeleton definition.
/// It is usefull for performing geometric operations
class GSkeleton : public Skeleton {
   
public:
   GSkeleton();
   GSkeleton(Skeleton &);
   GSkeleton(const GSkeleton &s);
   GSkeleton(const vector<Point3> &j, const vector<vector<int> > &g);
   virtual ~GSkeleton();
   
   /// Translate the i-th joint
   void translateJoint(int i, const Vector3 &t, char mode = 'T');
   /// Returns the position of joint i
   Point3 getJointPos(int i);
   /// Sets the position of joint i
   void setJointPos(int i, const Point3 &p);
   /// Return the number oj joints
   int nJoints() { return joints.size(); }
   /// Return the number oj bones
   int nBones() { return bones.size(); }
   /// Returns the segment of i-th bone
   const Segment3 getBoneSegment(int i) const;
   
   Vector3 getBoneUnitVector(int i) { 
      const Segment3 &bk = getBoneSegment(i);
      Vector3 v = bk[0] - bk[1];
      v = v/sqrt(v*v);
      return v;
   }
   
   int jointDegree(int i) { return graph[i].size(); } 
   
   /// Returns the mass center of the skeleton
   Point3 center() const { return _center; }
   /// Returns the radius of the bounded sphere that containts the skeleton
   Number radius() const { return _radius; }
   /// Computes distances from id to all joints on the skeleton
   /// @param id identifier of joint source
   void floodfill_Dijkstra(int id, bool kdistFlag=false);
   /// Sets parameters for animation purposes
   void setRelatedParamBone(int i, const pair<Number, int>&prm) { relatedParam[i]=prm; }
   /// Gets the animation parameters 
   const pair<Number, int>& getRelatedParamBone(int i) const { return relatedParam[i]; }
   /// Projects p over the bone vector
   Vector3 getBoneProjector(const Point3 &p, const int idbone);
   /// Computes the distance of p to bone idbone. Returns
   /// the distance and the parameter t that defines the closest on the bone
   Number getDistance(const Point3 &p, const int idbone, float &t);
   
   /// Tries to load a skeleton from file
   static GSkeleton* load(const string &filename);
   
   /// Export the skeleton in SKE format
   void export_to_ske(const char *filename);
   
   /// prints the bones ids
   void printBones();
   /// prints the branches
   void printBranches();
   /// prints the bones in PREV format
   void printBonesPREV();
   
   void convert2DualQuat();
   
   const vector<int> &getBonesInPrevFormat() const { return prev; }
   
   const OMR::Quaternion<> &getDualPart(int i) const { return dualQuats[i]; }
   const OMR::Quaternion<> &getQuatPart(int i) const { return transformation[i].getRot(); }
   
   Number pathLength(int s, int t);
   vector<unsigned> path(int s, int t);
private:
   /// Import a skeleton in SKE format
   void import_from_ske(const char *filename);
   
//private:
   void limits();
   /// Build the list of bones
   void genBonesList();
   
   ///
   void genControllersAndArtificialBones();
   
   /// Build a distance table for the skeleton's joints
   void buildDistanceBoneTable();
   
   ///
   Number getDistanceBetweenBone(unsigned int i, unsigned int j) {
      return dBonesTable[i][j];
   }
   
   /// Generates the branch list for a uskeleton
   void genBranches();
   ///
   void getBranch(int id);
   ///
   bool isJunction(int id) {
      return (graph[id].size() > 2);
   }
   bool isTerminal(int id) {
      return (graph[id].size() == 1);
   }
   
public:
   vector<Number>             d; // distances vector: it is used to perform the dijkstra algorithm
   vector<vector<int> >       graph; // the undirected graph is used for performing the Dijkstra path algorithm
   vector<Point3>             joints; // the array of joints
   vector<pair<int, int> >    bones; // the bones list
   vector<int>                prev; // describes the bones using a "previous format": bone = [jointId, jointPrevId]
   
   vector<vector<Number> >    dBonesTable; // a distance table
   vector<pair<Number, int> > relatedParam; // a table with parameters of a bone for each joint
   vector<bool>               k; // flag to specify special properties. TRUE(the joint is considered as a barrier), otherwise FALSE
   vector<float>              kdist;
   
   vector<bool>               visited; // used only for convenience
   vector<float>              D; // used only for convenience
   
   vector<vector<int> >       controller; // controllers bones
   vector<Vector3>            atbones;       // artificial bones used to get the rotation of a bone around itself
   vector<int>                orderList; // 
   
   Point3                     _center;
   Number                     _radius;
   string                     filename; // the file containing the skeleton
   
   vector<int>                closest_vertex; // the closest vertex id
   vector<Number>             min_distance_vertex; // the distance to the closest vertex
   vector<bool>               onlyvisible; // o closetvisible bone predomina sobre o 
                                           // bone mais proximo na metrica que inclui um caminho ao longo da superficie
   
   vector<vector<int> >       branches; // the array of branches of the skeleton
   
   vector<OMR::Transform<> >  transformation;
   vector<OMR::Quaternion<> > dualQuats;
   
protected:
   
   vector<int>  branch;
   vector<bool> ismarked; // auxiliar array used for the branches generation process
};

#endif
